/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frgzip_decompress.c                                */
/*  NOTE      =                                                    */
/*  DATE      = 2014/10/15 by geyh                                 */
/*******************************************************************/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <zlib.h>
#include <fcntl.h>
#include <stdio.h>

#include "frmem.h"
#include "frcomm.h"
#define GZIP_DEFAULT_MALLOC  1024


int frgzip_decompress(Byte *p_zdata, uLong u_l_nzdata,
                      char **pp_data, uLong *p_ndata)
{
    int i_err = 0;
    int i_tmp_len = 0, i_tmp_all = 0;
    z_stream st_stream = {0}; /* decompression stream */
    char *p_data = NULL, *p_tmp = NULL;
    int i_malloc = GZIP_DEFAULT_MALLOC, i_use = 0;
    //static char static_dummy_head[2] =
    //{
    //    0x8 + 0x7 * 0x10,
    //    (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
    //};
    
    //所有的数据
    p_data = (char *)frmalloc(i_malloc);
    if (p_data == NULL)
        return FR_FAIL;
    
    //临时的解压的数据
    p_tmp = (char *)frmalloc(GZIP_DEFAULT_MALLOC);
    if (p_tmp == NULL)
        goto err;
        
    st_stream.zalloc = (alloc_func)0;
    st_stream.zfree = (free_func)0;
    st_stream.opaque = (voidpf)0;
    st_stream.next_in = p_zdata;
    st_stream.avail_in = u_l_nzdata;
    
    if(inflateInit2(&st_stream, MAX_WBITS + 16) != Z_OK)
        goto err;

    do
    {
        st_stream.avail_out = GZIP_DEFAULT_MALLOC;
        st_stream.next_out = (Byte *)p_tmp;
        
        i_err = inflate(&st_stream, Z_NO_FLUSH);
        if (i_err < 0)
            goto err;
        
        //已经解码成功的长度
        i_tmp_len = GZIP_DEFAULT_MALLOC - st_stream.avail_out;
        i_tmp_all += i_tmp_len;
        if (i_tmp_all >= i_malloc)
        {
            char *p_remalloc = NULL;
            //remalloc
            p_remalloc = (char *)frmalloc(i_tmp_all + 1024);
            if (p_remalloc == NULL)
                goto err;
            
            memcpy(p_remalloc, p_data, i_malloc);
            i_malloc = i_tmp_all + 1024;
            
            frfree(p_data);
            p_data = p_remalloc;
        }
        memcpy(p_data + i_use, p_tmp, i_tmp_len);
        i_use += i_tmp_len;
        
    } while(0 == st_stream.avail_out);

    *p_ndata = i_tmp_all;
    p_data[i_tmp_all] = '\0';
    *pp_data = p_data;
    frfree(p_tmp);
    inflateEnd(&st_stream);
    
    return FR_SUCC;
err:

    if (p_data)
        frfree(p_data);
    if (p_tmp)
        frfree(p_tmp);
    inflateEnd(&st_stream);
    return FR_FAIL;
}

//inflateInit2->inflateInit
int frgzip_flush_decompress(Byte *p_zdata, uLong u_l_nzdata,
                      char **pp_data, uLong *p_ndata)
{
    int i_err = 0;
    int i_tmp_len = 0, i_tmp_all = 0;
    z_stream st_stream = {0}; /* decompression stream */
    char *p_data = NULL, *p_tmp = NULL;
    int i_malloc = GZIP_DEFAULT_MALLOC, i_use = 0;
    //static char static_dummy_head[2] =
    //{
    //    0x8 + 0x7 * 0x10,
    //    (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
    //};

    //所有的数据
    p_data = (char *)frmalloc(i_malloc);
    if (p_data == NULL)
        return FR_FAIL;

    //临时的解压的数据
    p_tmp = (char *)frmalloc(GZIP_DEFAULT_MALLOC);
    if (p_tmp == NULL)
        goto err;

    st_stream.zalloc = (alloc_func)0;
    st_stream.zfree = (free_func)0;
    st_stream.opaque = (voidpf)0;
    st_stream.next_in = p_zdata;
    st_stream.avail_in = u_l_nzdata;

    if(inflateInit(&st_stream) != Z_OK)
        goto err;

    do
    {
        st_stream.avail_out = GZIP_DEFAULT_MALLOC;
        st_stream.next_out = (Byte *)p_tmp;

        //i_err = inflateSync(&st_stream);
        i_err = inflate(&st_stream, Z_NO_FLUSH);
        if (i_err < 0)
            goto err;

        //已经解码成功的长度
        i_tmp_len = GZIP_DEFAULT_MALLOC - st_stream.avail_out;
        i_tmp_all += i_tmp_len;
        if (i_tmp_all >= i_malloc)
        {
            char *p_remalloc = NULL;
            //remalloc
            p_remalloc = (char *)frmalloc(i_tmp_all + 1024);
            if (p_remalloc == NULL)
                goto err;

            memcpy(p_remalloc, p_data, i_malloc);
            i_malloc = i_tmp_all + 1024;

            frfree(p_data);
            p_data = p_remalloc;
        }
        memcpy(p_data + i_use, p_tmp, i_tmp_len);
        i_use += i_tmp_len;

    } while(0 == st_stream.avail_out);

    *p_ndata = i_tmp_all;
    p_data[i_tmp_all] = '\0';
    *pp_data = p_data;
    frfree(p_tmp);
    inflateEnd(&st_stream);

    return FR_SUCC;
    err:

    if (p_data)
        frfree(p_data);
    if (p_tmp)
        frfree(p_tmp);
    inflateEnd(&st_stream);
    return FR_FAIL;
}
